import uuid
from datetime import datetime

from gis.common import track_logging
from gis.common.django_ext.models import paginate
from gis.common.exceptions import BizException
from itpay.core.agency import agency_service
from itpay.core.agency.const import AgencyType
from itpay.utils import maestro_tracker
from .errors import *
from .models import Account as MchAccount
from .const import MchType

_LOGGER = track_logging.getLogger(__name__)


def _check_mch_name_duplicate(name):
    if MchAccount.objects.filter(name=name).exists():
        raise BizException(ERROR_MCH_NAME_DUPLICATE)


def add_mch(name, enable=False, create_order_url=None, recharge_order_url=None, chase_order_url=None,
            get_charge_info_url=None, fail_order_url=None, mch_type=None):
    """
    新增商户
    """
    assert name
    assert not mch_type or isinstance(mch_type, MchType)
    _check_mch_name_duplicate(name)
    api_key = str(uuid.uuid4())
    mch = MchAccount(name=name, enable=enable, api_key=api_key, create_order_url=create_order_url,
                     recharge_order_url=recharge_order_url, chase_order_url=chase_order_url,
                     get_charge_info_url=get_charge_info_url, fail_order_url=fail_order_url)
    if mch_type:
        mch.mch_type = mch_type
    mch.save()
    try:
        maestro_tracker.track_maestro_mch_create(mch.id, int(datetime.strftime(datetime.now(), '%s')))
    except Exception:
        _LOGGER.info("track_maestro_mch_create error {}".format(mch.id), exc_info=True)

    return mch.to_dict(exclude=['api_key'])


def get_mch(mch_id, exclude_api_key=True):
    if exclude_api_key:
        return _get_mch(mch_id).to_dict(exclude=['api_key'])
    return _get_mch(mch_id).to_dict()


def _get_mch(mch_id):
    mch = MchAccount.objects.filter(pk=mch_id).first()
    if not mch:
        raise BizException(ERROR_MCH_NOT_EXISTS, mch_id)
    return mch


def enable_mch(mch_id):
    """
    启用商户
    :param mch_id:
    :return:
    """
    assert mch_id
    mch = _get_mch(mch_id)
    mch.enable = True
    mch.save()


def disable_mch(mch_id):
    """
    禁用商户
    :param mch_id:
    :return:
    """
    assert mch_id
    mch = _get_mch(mch_id)
    mch.enable = False
    mch.save()


def list_mch(page_no, page_size, enable=None, mch_type=None):
    assert not mch_type or isinstance(mch_type, MchType)
    query = MchAccount.objects.filter()
    if enable is not None:
        query = query.filter(enable=enable)
    if mch_type:
        query = query.filter(mch_type=mch_type)
    return query.count(), [e.to_dict(exclude=['api_key']) for e in paginate(query, page_no, page_size)]


def bind_mch_to_agency(agency, mch_ids):
    if not mch_ids:
        return
    # 创建子代时，子代绑定商户不能超出总代绑定商户限制
    if AgencyType(agency.agency_type) == AgencyType.NORMAL_AGENCY:
        admin_agency = agency_service.get_agency_by_id(agency.parent_id, with_mch_info=True)
        admin_mch_ids = [mch['id'] for mch in admin_agency['mchs']]
        if not set(admin_mch_ids) >= set(mch_ids):
            raise BizException(ERROR_MCH_NOT_BELONG_ADMIN_AGENCY)
    for mch_id in mch_ids:
        mch = _get_mch(mch_id)
        agency.mchs.add(mch)


def update_mch(mch_id, name=None, enable=None, update_api_key=False, create_order_url=None,
               recharge_order_url=None, chase_order_url=None, get_charge_info_url=None, fail_order_url=None):
    mch = _get_mch(mch_id)
    if name:
        mch.name = name
    if enable is not None:
        mch.enable = enable
    if update_api_key:
        mch.api_key = str(uuid.uuid4())
    if create_order_url:
        mch.create_order_url = create_order_url
    if recharge_order_url:
        mch.recharge_order_url = recharge_order_url
    if chase_order_url:
        mch.chase_order_url = chase_order_url
    if get_charge_info_url:
        mch.get_charge_info_url = get_charge_info_url
    if fail_order_url:
        mch.fail_order_url = fail_order_url
    mch.save()


def bind_mch_to_bulletin(bulletin, mch_ids):
    if not mch_ids:
        return
    for mch_id in mch_ids:
        mch = _get_mch(mch_id)
        bulletin.mchs.add(mch)
